<%#
 Copyright 2013-2025 the original author or authors from the JHipster project.

 This file is part of the JHipster project, see https://www.jhipster.tech/
 for more information.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      https://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-%>
import { inject, Injectable, SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
<%_ if (enableTranslation) { _%>
import { TranslateService } from '@ngx-translate/core';

import { translationNotFoundMessage } from 'app/config/translation.config';
<%_ } _%>

export type AlertType = 'success' | 'danger' | 'warning' | 'info';

export interface AlertModel {
  id: number;
  type: AlertType;
  message?: string;
<%_ if (enableTranslation) { _%>
  translationKey?: string;
  translationParams?: Record<string, unknown>;
<%_ } _%>
  timeout?: number;
  toast?: boolean;
  position?: string;
  close?: (alerts: AlertModel[]) => void;
}

@Injectable({
  providedIn: 'root',
})
export class AlertService {
  timeout = 5000;
  toast = false;
  position = 'top right';

  // unique id for each alert. Starts from 0.
  private alertId = 0;
  private alerts: AlertModel[] = [];

  private readonly sanitizer = inject(DomSanitizer);
<%_ if (enableTranslation) { _%>
  private readonly translateService = inject(TranslateService);
<%_ } _%>

  clear(): void {
    this.alerts = [];
  }

  get(): AlertModel[] {
    return this.alerts;
  }

  /**
   * Adds alert to alerts array and returns added alert.
   * @param alertToAdd Alert to add. If `timeout`, `toast` or `position` is missing then applying default value.
<%_ if (enableTranslation) { _%>
   *                   If `translateKey` is available then it's translation else `message` is used for showing.
<%_ } _%>
   * @param extAlerts  If missing then adding `alert` to `AlertService` internal array and alerts can be retrieved by `get()`.
   *                   Else adding `alert` to `extAlerts`.
   * @returns  Added alert
   */
  addAlert(alertToAdd: Omit<AlertModel, 'id'>, extAlerts?: AlertModel[]): AlertModel {
    const alert: AlertModel = { ...alertToAdd, id: this.alertId++ };

<%_ if (enableTranslation) { _%>
    if (alert.translationKey) {
      const translatedMessage = this.translateService.instant(alert.translationKey, alert.translationParams);
      // if translation key exists
      if (translatedMessage !== `${translationNotFoundMessage}[${alert.translationKey}]`) {
        alert.message = translatedMessage;
      }
      alert.message ??= alert.translationKey;
    }
<%_ } _%>

    alert.message = this.sanitizer.sanitize(SecurityContext.HTML, alert.message ?? '') ?? '';
    alert.timeout ??= this.timeout;
    alert.toast ??= this.toast;
    alert.position ??= this.position;
    alert.close = (alertsArray: AlertModel[]) => this.closeAlert(alert.id, alertsArray);

    (extAlerts ?? this.alerts).push(alert);

    if (alert.timeout > 0) {
      setTimeout(() => {
        this.closeAlert(alert.id, extAlerts ?? this.alerts);
      }, alert.timeout);
    }

    return alert;
  }

  private closeAlert(alertId: number, extAlerts?: AlertModel[]): void {
    const alerts = extAlerts ?? this.alerts;
    const alertIndex = alerts.map(alert => alert.id).indexOf(alertId);
    // if found alert then remove
    if (alertIndex >= 0) {
      alerts.splice(alertIndex, 1);
    }
  }
}
